package ws

import (
	"fmt"
	"gim-server/apis/ws/notify_open_api"
	"gim-server/config"
	"gim-server/consts"
	"gim-server/errs"
	"gim-server/sdk"
	"gim-server/utils"
	"github.com/dgrijalva/jwt-go"
	"github.com/gin-gonic/gin"
	"github.com/gorilla/websocket"
	"net/http"
	"time"
)

type connInfo struct {
	Uid         string `json:"uid"`
	AppID       string `json:"app_id"`
	Platform    string `json:"platform"`
	OnFrontDesk bool   `json:"on_front_desk"`
	ClientIp    string `json:"client_ip"`
	ServerIp    string `json:"server_ip"`
}

var (
	imKeyFmt = "wscli:%v"
	upgrader = websocket.Upgrader{
		CheckOrigin: func(r *http.Request) bool {
			return true
		},
	}
	imClients = make(map[string]*websocket.Conn)
)

func ws(ctx *gin.Context) {
	ip, _ := utils.ExternalIP()
	tokenInfo, err := utils.ParseToken(config.GetCfg().SignKey, ctx.Request.Header.Get(consts.Token))
	if err != nil {
		utils.ERR(ctx, &utils.ErrArgs{
			Code: errs.ApiTokenErr,
			Err:  err,
		})
		return
	}
	claims := tokenInfo.Claims.(jwt.MapClaims)
	user := connInfo{
		Uid:         claims[consts.UID].(string),
		AppID:       ctx.Request.Header.Get(consts.AppID),
		Platform:    ctx.Request.Header.Get(consts.Platform),
		OnFrontDesk: true,
		ClientIp:    ctx.ClientIP(),
		ServerIp:    ip.String(),
	}
	imKey := fmt.Sprintf(imKeyFmt, user.Uid)
	rds := sdk.Redis(ctx)
	userStr, err := utils.JsonMarshal(user)
	if err != nil {
		utils.ERR(ctx, &utils.ErrArgs{
			Code: errs.ApiSrvErr,
			Err:  err,
		})
		return
	}
	rds.Set(imKey, string(userStr), time.Hour*24*365)
	//升级get请求为webSocket协议
	ws, err := upgrader.Upgrade(ctx.Writer, ctx.Request, nil)
	if err != nil {
		utils.ERR(ctx, &utils.ErrArgs{
			Code: errs.ApiSrvErr,
			Err:  err,
		})
		return
	}
	defer func() {
		_ = ws.Close()
		delete(imClients, imKey)
		user.OnFrontDesk = false
		userStr, err = utils.JsonMarshal(user)
		if err != nil {
			utils.ERR(ctx, &utils.ErrArgs{
				Code: errs.ApiSrvErr,
				Err:  err,
			})
			return
		}
		rds.Set(imKey, string(userStr), time.Hour*24*365)
		notify_open_api.NotifyOnline(&notify_open_api.NotifyOnlineArgs{
			AppID:  user.AppID,
			UID:    user.Uid,
			Online: false,
		})
	}()
	if err = ws.PingHandler()("#"); err != nil {
		utils.ERR(ctx, &utils.ErrArgs{
			Code: errs.ApiSrvErr,
			Err:  err,
		})
		return
	}
	notify_open_api.NotifyOnline(&notify_open_api.NotifyOnlineArgs{
		AppID:  user.AppID,
		UID:    user.Uid,
		Online: true,
	})
	fmt.Printf("用户连接成功：%+v\n", user)
	oldWs, ok := imClients[imKey]
	if ok {
		_ = oldWs.WriteJSON(&MsgDto{
			Event: SybLogout,
		})
		_ = oldWs.Close()
		delete(imClients, imKey)
	}
	imClients[imKey] = ws
	time.AfterFunc(time.Second, func() {
		_ = ws.WriteJSON(
			&MsgDto{
				Event: SybConnected,
				Data:  user,
			})
	})
	for {
		//心跳
		msg := new(MsgDto)
		if err := ws.ReadJSON(msg); err != nil {
			break
		}
		if err := ws.WriteJSON(msg); err != nil {
			break
		}
	}
}

func sendMsg(uid string, dto *MsgDto) error {
	conn, ok := imClients[fmt.Sprintf(imKeyFmt, uid)]
	if ok {
		return conn.WriteJSON(dto)
	}
	return nil
}
